/**
 * Copyright (C) 2012 The SkyTvOS Project
 * <p/>
 * Version     Date           Author
 * ─────────────────────────────────────
 * 2015年1月6日         Root.Lu
 */

package com.coocaa.x.framework.app;

import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Log;

import com.coocaa.x.framework.app.CoocaaApplication.NetChangeReceiver.NetChangeReceiverListener;
import com.coocaa.x.framework.app.CoocaaApplication.PackageReceiver.InstallUninstallInterface;
import com.coocaa.x.framework.data.JObject;
import com.coocaa.x.framework.utils.Android;
import com.coocaa.x.framework.utils.FansChannelUpgrade;
import com.coocaa.x.framework.utils.LiteHandlerThread;
import com.coocaa.x.framework.utils.LogUtils;
import com.coocaa.x.framework.utils.Storage;
import com.coocaa.x.framework.utils.ThirdMac;
import com.coocaa.x.provider.xprovider.XProviderManager;
import com.coocaa.x.service.XServiceManager;
import com.coocaa.x.service.liteservice.LiteServiceManager;
import com.skyworth.framework.skycommondefine.SkyBroadcast;
import com.skyworth.framework.skysdk.android.SkySystemUtil;
import com.skyworth.framework.skysdk.ipc.SkyContext;
import com.skyworth.framework.skysdk.properties.SkyGeneralProperties;
import com.skyworth.framework.skysdk.properties.SkySystemProperties;
import com.umeng.analytics.MobclickAgent;

import org.litepal.LitePalApplication;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;

public class CoocaaApplication extends Application implements Thread.UncaughtExceptionHandler {

    private static ExecutorService executor = null;
    private static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
    private static String macAddress = "";
    private static String mChannel = "SkyCoocaa";


    private static Thread.UncaughtExceptionHandler uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
        private String log(Throwable ex) {
            String ret = ex.toString() + "\n";
            StackTraceElement[] es = ex.getStackTrace();
            for (StackTraceElement e : es) {
                String file_line = "    " + e.getClassName() + "." + e.getMethodName() + "("
                        + e.getFileName() + "@" + e.getLineNumber() + ")";
                ret += file_line + "\n";
            }
            return ret;
        }

        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            LogUtils.e("e", thread.getName() + " uncaughtException:\n" + log(ex));
        }
    };


    public static synchronized void post(Runnable r) {
        Thread t = new Thread(r);
        t.setUncaughtExceptionHandler(uncaughtExceptionHandler);
        t.setPriority(Thread.MIN_PRIORITY);
        t.start();
//        if (executor == null) {
////            executor = Executors.newCachedThreadPool(new ThreadFactory() {
////                @Override
////                public Thread newThread(Runnable r) {
////                    Thread thread = new Thread(r, "AsyncTask" + System.currentTimeMillis());
////                    thread.setPriority(Thread.MIN_PRIORITY);
////                    thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
////                    return thread;
////                }
////            });
//            executor = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS, queue,
//                    new ThreadFactory() {
//                        @Override
//                        public Thread newThread(Runnable r) {
//                            Thread thread = new Thread(r, "AsyncTask" + System.currentTimeMillis());
//                            thread.setPriority(Thread.MIN_PRIORITY);
//                            thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
//                            return thread;
//                        }
//                    });
//        }
//        executor.execute(r);
    }


    private static Context mContext = null;

    public static void setContext(Context c) {
        mContext = c;
    }

    public static Context getContext() {
        return mContext;
    }

    private static CoocaaWebService cws = null;
    private static CoocaaApplication application = null;

    protected static void uninstallSelf(Context c) {
        String command = "pm uninstall " + c.getPackageName();
        try {
            Process process = Runtime.getRuntime().exec(command);
            process.waitFor();
            process.getOutputStream().toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static long applicationStartTime = 0;
    private static final long CRASH_GATE = 5000;
    private static final String DIED_COUNT = "died_count";
    private static final String FIRST_DIED_TIME = "first_died_time";

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        LogUtils.e("AndroidRuntime", LogUtils.throwable2String(ex));
        SharedPreferences sp = getSharedPreferences("rec." + Android.getCurrentProcessName(this), Context.MODE_WORLD_READABLE
                + Context.MODE_WORLD_WRITEABLE);
        long current = System.currentTimeMillis();
        int died_count = sp.getInt(DIED_COUNT, 0);
        long crashTime = current - applicationStartTime;
        if (crashTime <= CRASH_GATE) {
            if (died_count == 0)
                sp.edit().putLong(FIRST_DIED_TIME, current).commit();
            long first_died_time = sp.getLong(FIRST_DIED_TIME, current);
            died_count += 1;
            if (died_count >= 5) { //连续挂5次 并且第五挂发生在首次挂掉的7天以内
                if ((current - first_died_time) < 604800000)
                    uninstallSelf(this);
                else {
                    sp.edit().putLong(FIRST_DIED_TIME, current).commit();
                    sp.edit().putInt(DIED_COUNT, 0).commit();
                }
            } else
                sp.edit().putInt(DIED_COUNT, died_count).commit();
        } else
            sp.edit().putInt(DIED_COUNT, 0).commit();

        MobclickAgent.reportError(this, ex);
        MobclickAgent.onKillProcess(this);
        System.exit(0);
    }

    private static boolean bCreated = false;

    public static void waiting4me() {
        LiteHandlerThread.checkMainThread();
        while (!bCreated)
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }

    @Override
    public void onCreate() {
        mContext = getApplicationContext();
        LogUtils.d("sss", "CoocaaApplication onCreate Thread:" + Thread.currentThread());
        super.onCreate();
        applicationStartTime = System.currentTimeMillis();
        Thread.setDefaultUncaughtExceptionHandler(this);
        SkyContext.context = getApplicationContext();
        application = this;
        XProviderManager.init(getContext());
        setResolutionDiv(mContext);
        LitePalApplication.initialize(mContext);
        initCoocaaWebService();
        initNetChangeReceiver();
        initPackageReceiver();
        initOneKeyRestoreReceiver();
//        initLiteServiceReceiver();
        Storage.setContext(mContext);
        XServiceManager.init(mContext);
        bCreated = true;
    }

    private void initOneKeyRestoreReceiver() {
        IntentFilter installFilter = new IntentFilter();
        installFilter.addAction(SkyBroadcast.SKY_BCT_RECOVERY_START);
        registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                LogUtils.i("OneKey", "SKY_BCT_RECOVERY_START!!!!");
                post(new Runnable() {
                    @Override
                    public void run() {
                        LogUtils.i("OneKey", "Android.clearAppData!!!!");
                        Android.clearAppData(getPackageName());
                        LogUtils.i("OneKey", "Android.clearAppData$$$$$$$$");
                        android.os.Process.killProcess(android.os.Process.myPid());
                        System.exit(0);
                    }
                });
            }
        }, installFilter);
    }

    public static float mDiv = 1;
    public static float mDpi = 1;

    public static synchronized void setResolutionDiv(Context context) {
        int width = SkySystemUtil.getDisplayWidth(context);
        LogUtils.d("the dpi is " + SkySystemUtil.getDisplayDensity(context));
        mDiv = width / 1920.0f;
        mDpi = mDiv / SkySystemUtil.getDisplayDensity(context);
        LogUtils.d("the div is " + mDiv);
    }

    public static int Div(int x) {
        return (int) (x * mDiv);
    }

    public static int Dpi(int x) {
        return (int) (x * mDpi);
    }

    private void initLiteServiceReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(LiteServiceManager.LITE_SERVICE_ON_CREATE_BROADCAST_ACTION);
        filter.addAction(LiteServiceManager.LITE_SERVICE_ON_DESTROY_BROADCAST_ACTION);
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context arg0, Intent arg1) {
                String action = arg1.getAction();
                if (action.equals(LiteServiceManager.LITE_SERVICE_ON_CREATE_BROADCAST_ACTION)) {
//                    new Thread(new Runnable() {
//                        @Override
//                        public void run() {
//                            try {
//                                String services = (String) Android.getMetaData(getContext(),
//                                        getContext().getPackageName(), APP_SERVICE_ENTRY);
//                                String[] _services = services.split("\\|");
//                                for (String service : _services)
//                                    XServiceManager.registerService(getPackageName(), service);
//                            } catch (Exception e) {
//                            }
//                        }
//                    }).start();
                }
            }
        }, filter);
    }

    private void initCoocaaWebService() {
        cws = createCoocaaWebService();
        cws.init();
    }

    private void initPackageReceiver() {
        IntentFilter installFilter = new IntentFilter();
        installFilter.addAction("android.intent.action.PACKAGE_ADDED");
        installFilter.addAction("android.intent.action.PACKAGE_REMOVED");
        installFilter.addDataScheme("package");
        getContext().registerReceiver(PackageReceiver.getInstance(), installFilter);
    }

    private void initNetChangeReceiver() {
        IntentFilter netChangeFilter = new IntentFilter();
        netChangeFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        mContext.registerReceiver(NetChangeReceiver.getInstance(), netChangeFilter);
    }

    /**
     * TODO 重载此方法，已实现自定义webservice接口
     *
     * @return CoocaaWebService 对方法返回值的说明
     * @author lu
     * @version 2015年6月2日 以修改时间为准
     * @see 参考转向，也就是相关主题
     */
    protected CoocaaWebService createCoocaaWebService() {
        return new CoocaaWebService();
    }

    public static class CoocaaVersion extends JObject {
        public int major = -1;
        public int minor = -1;
        public int rev = -1;
    }

    private static CoocaaVersion mCoocaaVersion = null;

    public static synchronized CoocaaVersion getCoocaaVersion() throws Exception {
        if (mCoocaaVersion == null) {
            mCoocaaVersion = new CoocaaVersion();
            try {
                String path = Environment.getRootDirectory() + "/vendor/TianciVersion";
                if (new File(path).exists()) {
                    StringBuilder sb = new StringBuilder();
                    String s = "";
                    BufferedReader br = new BufferedReader(new FileReader(new File(path)));
                    if ((s = br.readLine()) != null) {
                        sb.append(s + "\n");
                    }
                    br.close();
                    String[] strs = s.split("\\.");
                    if (strs != null && strs.length > 1) {
                        mCoocaaVersion.major = Integer.valueOf(strs[0]);
                        mCoocaaVersion.minor = Integer.valueOf(strs[1]);
                    }
                } else {
                    mCoocaaVersion = null;
                    throw new Exception("There has no /vendor/TianciVersion");
                }
            } catch (Exception e) {
                mCoocaaVersion = null;
                throw new Exception("There has no /vendor/TianciVersion");
            }
        }
        return mCoocaaVersion;
    }

    public static boolean isCoocaaSystem() {
//        return false;
        CoocaaVersion version = null;
        try {
            version = getCoocaaVersion();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (version != null && version.major >= 4)
            return true;
        return false;
    }

    public static String getMAC() {
        if (macAddress != null && !macAddress.equals("")) {
            return macAddress;
        }
        synchronized (macAddress) {
            Context context = CoocaaApplication.getContext();
            String mac = "";
            try {
                mac = XServiceManager.getLiteConfigService().getStringValue("mac", "");
            } catch (Exception e) {
                e.printStackTrace();
            }
            LogUtils.d("mac", "getMAC  111mac:" + mac);
            if (!mac.equals("")) {
                macAddress = mac;
                return mac;
            }
            mac = SkySystemProperties.getProperty("third.get.mac");
            boolean flag = saveMac(mac, "222");
            if (flag) {
                macAddress = mac;
                return mac;
            }
            mac = ThirdMac.getEtherMac();
            flag = saveMac(mac, "333");
            if (flag) {
                macAddress = mac;
                return mac;
            }
            mac = ThirdMac.getWifiMac();
            flag = saveMac(mac, "444");
            if (flag) {
                macAddress = mac;
                return mac;
            }
            android.net.wifi.WifiManager wifi = (android.net.wifi.WifiManager) context
                    .getSystemService(Context.WIFI_SERVICE);
            mac = wifi.getConnectionInfo().getMacAddress();
            flag = saveMac(mac, "555");
            if (flag) {
                macAddress = mac;
                return mac;
            }
            if (mac == null)
                return "";
            return mac;
        }
    }

    private static boolean saveMac(String mac, String log) {
        if (mac != null) {
            mac = mac.replace(":", "").trim();
            LogUtils.d("mac", "getMAC  " + log + "mac:" + mac);
            if (!mac.equals("") && !mac.equals("000000000000") && !mac.equals("0")) {
                try {
                    XServiceManager.getLiteConfigService().saveStringConfig("mac", mac);
                } catch (Exception e) {
                    return false;
                }
                return true;
            }
        }
        return false;
    }

    public static String getAppVersionCode() {
        Context context = CoocaaApplication.getContext();
        String version = "";
        String pkgname = context.getPackageName();
        try {
            version = String
                    .valueOf(context.getPackageManager().getPackageInfo(pkgname, 0).versionCode);
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        LogUtils.d("lqw", "getAPPVersionCode:" + version);
        return version;
    }

    public static String getAPPVersion() {
        Context context = CoocaaApplication.getContext();
        String version = "";
        String pkgname = context.getPackageName();
        try {
            version = context.getPackageManager().getPackageInfo(pkgname, 0).versionName;
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        LogUtils.d("lqw", "getAPPVersionName:" + version);
        return version;
    }

    /**
     * ro.build.skymid ： 芯片
     * <p/>
     * ro.build.skymodel：机芯
     * <p/>
     * ro.build.skytype：机型
     * <p/>
     * 比如 海思E6000平台的：
     * <p/>
     * [ro.build.skymid]: [Hi3751V500]
     * <p/>
     * [ro.build.skymodel]: [8H83]
     * <p/>
     * [ro.build.skytype]: [E6000]
     *
     * @author lu
     * @version 2015年4月9日
     * @see 参考转向，也就是相关主题
     */
    public static class DeviceModeMidType extends JObject {
        public String skymid = "";
        public String skymodel = "";
        public String skytype = "";

        public DeviceModeMidType(String skymid, String skymodel, String skytype) {
            this.skymid = skymid;
            this.skymodel = skymodel;
            this.skytype = skytype;
        }
    }

    private static DeviceModeMidType mDeviceModeMidType = null;

    public static synchronized DeviceModeMidType getDeviceModeMidType() {
        if (mDeviceModeMidType == null) {
            String skymid = SystemProperties.get("ro.build.skymid");
            String skymodel = SystemProperties.get("ro.build.skymodel");
            String skytype = SystemProperties.get("ro.build.skytype");
            mDeviceModeMidType = new DeviceModeMidType(skymid, skymodel, skytype);
        }
        return mDeviceModeMidType;
    }

    public static class NetChangeReceiver extends BroadcastReceiver {
        private static NetChangeReceiver instance = new NetChangeReceiver();

        public synchronized static NetChangeReceiver getInstance() {
            return instance;
        }

        public static interface NetChangeReceiverListener {
            void onNetStateChanged(boolean bConnected);
        }

        private List<NetChangeReceiverListener> list = new ArrayList<NetChangeReceiverListener>();

        public void addListener(NetChangeReceiverListener listener) {
            synchronized (list) {
                list.add(listener);
            }
        }

        public void removeListener(NetChangeReceiverListener listener) {
            synchronized (list) {
                if (list.contains(listener)) {
                    list.remove(listener);
                }
            }
        }

        @Override
        public void onReceive(Context mContext, Intent intent) {
            LogUtils.d("net", "onReceive---------");
            boolean bConnected = false;
            ConnectivityManager connectivityManager = (ConnectivityManager) mContext
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo activeNetWork = null;
            activeNetWork = connectivityManager.getActiveNetworkInfo();
            // int netType = -1;
            if (activeNetWork != null) {
                // netType = activeNetWork.getType();
                bConnected = activeNetWork.isConnected();
            }

            final boolean _bConnected = bConnected;

            synchronized (list) {
                for (final NetChangeReceiverListener l : list) {
                    post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                l.onNetStateChanged(_bConnected);
                            } catch (Exception e) {
                            }
                        }
                    });
                }
            }
        }
    }

    public static void addNetChangedListener(NetChangeReceiverListener listener) {
        NetChangeReceiver.getInstance().addListener(listener);
    }

    public static void removeNetChangedListener(NetChangeReceiverListener listener) {
        NetChangeReceiver.getInstance().removeListener(listener);
    }

    public static class PackageReceiver extends BroadcastReceiver {
        private static PackageReceiver instance = new PackageReceiver();

        public synchronized static PackageReceiver getInstance() {
            return instance;
        }

        public static interface InstallUninstallInterface {
            public void installEvent(Intent i);

            public void uninstallEvent(Intent i);
        }

        private List<InstallUninstallInterface> list = new ArrayList<InstallUninstallInterface>();

        public void addListener(InstallUninstallInterface i) {
            synchronized (list) {
                list.add(i);
            }
        }

        public void removeListener(InstallUninstallInterface i) {
            synchronized (list) {
                list.remove(i);
            }
        }

        @Override
        public void onReceive(Context c, final Intent intent) {
            synchronized (list) {
                if (list.size() < 1) {
                    return;
                }
                if (intent.getAction().equals("android.intent.action.PACKAGE_ADDED")) { // install
                    LogUtils.d("intent", "android.intent.action.PACKAGE_ADDED");
                    for (final InstallUninstallInterface i : list) {
                        post(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    i.installEvent(intent);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                }

                if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) { // uninstall
                    LogUtils.d("intent", "android.intent.action.PACKAGE_REMOVED");
                    for (final InstallUninstallInterface i : list) {
                        post(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    i.uninstallEvent(intent);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                }
            }
        }
    }

    public static void addPackageListener(InstallUninstallInterface listener) {
        PackageReceiver.getInstance().addListener(listener);
    }

    public static void removePackageListener(InstallUninstallInterface listener) {
        PackageReceiver.getInstance().removeListener(listener);
    }

    public static CoocaaWebService getCoocaaWebService() {
        return application._getCoocaaWebService();
    }

    protected CoocaaWebService _getCoocaaWebService() {
        return cws;
    }

    public static boolean installWithPackageInstaller() {
        if (SkyGeneralProperties.getBoolProperty("x_install_with_packageinstaller"))
            return true;
        return !SkyGeneralProperties.getBoolProperty("HIGH_MEMORY");
    }


    public static boolean isRoot() {
        return application._isRoot();
    }

    protected boolean _isRoot() {
//        if (isCoocaaSystem()) {
//            // 这个general_config配置很坑爹，估计后续会改，但仅在酷开系统有效
//            boolean value = SkyGeneralProperties.getBoolProperty("HIGH_MEMORY");
//            if (!value)
//                return false;
//        }
        ApplicationInfo appInfo = null;
        PackageManager pm = mContext.getPackageManager();
        try {
            appInfo = pm.getApplicationInfo(mContext.getPackageName(), 0);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
        if (appInfo != null && appInfo.uid == 1000)
            return true;
        return false;
    }

    public static String getContentChannel() {
//        return application._getContentChannel();
        return mChannel;
    }

    public static void setContentChannel(String channel) {
        mChannel = channel;
    }

    protected String _getContentChannel() {
        Context context = CoocaaApplication.getContext();
        String channel = null;
        channel = (String) Android
                .getMetaData(context, context.getPackageName(), "CONTENT_CHANNEL");
        if (channel == null || channel.equals("")) {
            LogUtils.e("getContentChannel failed,ues SkyCoocaa instead!!");
            channel = "SkyCoocaa";
        }
        return channel;
    }

    private static final String SYS_BOOT_COMPLETED = "sys.boot_completed";
    private static final String DEV_BOOT_COMPLETED = "dev.bootcomplete";

    public static void wait4SystemBootcompleteFlag() {
        LiteHandlerThread.checkMainThread();
        int count = 0;
        while (true && count < 600) {
            String sys = SkySystemProperties.getProperty(SYS_BOOT_COMPLETED);
            String dev = SkySystemProperties.getProperty(DEV_BOOT_COMPLETED);
            if ((sys != null && sys.equals("1")))
                break;
            if ((dev != null && dev.equals("1")))
                break;
            try {
                Thread.sleep(100);
                count++;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (count < 600)
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }

    private static final String FIRSTSTART = "ccapp_config_fs_";

    public static boolean isFirstStartToday(String key) {
        try {
            long _current = System.currentTimeMillis();
            long _saved = XServiceManager.getLiteConfigService().getLongValue(FIRSTSTART + key, 0);
            XServiceManager.getLiteConfigService().saveLongConfig(FIRSTSTART + key, _current);
            Date saved = new Date(_saved);
            Date current = new Date(_current);
            if (current.after(saved)) {
                if (current.getYear() > saved.getYear())
                    return true;
                if (current.getMonth() > saved.getMonth())
                    return true;
                if (current.getDate() > saved.getDate())
                    return true;
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return false;
    }
}
